// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gopher

import (
	"appengine"
	"appengine/datastore"
	"appengine/memcache"
	"fmt"
	"net/http"
	"time"
)

// The init function is called when your application starts.
func init() {
	// Register a handle for /progginator URLs.
	http.HandleFunc("/progginator", progginator)
	http.HandleFunc("/progginator_", progginator_)
	http.HandleFunc("/progginator__", progginator__)
	http.HandleFunc("/progginator___", progginator___)
	http.HandleFunc("/fetch", fetch)
}

func progginator(w http.ResponseWriter, r *http.Request) {
	begin := time.Now() // OMIT
	c := appengine.NewContext(r)
	hnItems := hackernewsItems(c)
	pgItems := proggitItems(c)
	w.Header().Add("Content-Type", "text/plain; charset=utf-8")
	for _, item := range hnItems {
		fmt.Fprintf(w, "%s: %s\n", item.Title, item.URL)
	}
	for _, item := range pgItems {
		fmt.Fprintf(w, "%s: %s\n", item.Title, item.URL)
	}
	c.Infof("progginator: %s", time.Since(begin)) // OMIT
}

// STOP OMIT

func progginator_(w http.ResponseWriter, r *http.Request) {
	begin := time.Now() // OMIT
	c := appengine.NewContext(r)
	results := make(chan []Item)
	go func() {
		results <- hackernewsItems(c)
	}()
	go func() {
		results <- proggitItems(c)
	}()
	w.Header().Add("Content-Type", "text/plain; charset=utf-8")
	for i := 0; i < 2; i++ {
		items := <-results
		for _, item := range items {
			fmt.Fprintf(w, "%s: %s\n", item.Title, item.URL)
		}
	}
	c.Infof("progginator_: %s", time.Since(begin)) // OMIT
}

// STOP OMIT

type Feed struct {
	Items []Item `datastore:",noindex"`
}

// STOP OMIT

func fetch(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	done := make(chan error)
	go func() {
		key := datastore.NewKey(c, "Feed", "hackernews", 0, nil)
		val := &Feed{Items: hackernewsItems(c)}
		_, err := datastore.Put(c, key, val)
		done <- err
	}()
	go func() {
		key := datastore.NewKey(c, "Feed", "proggit", 0, nil)
		val := &Feed{Items: proggitItems(c)}
		_, err := datastore.Put(c, key, val)
		done <- err
	}()
	// Wait for goroutines
	// ...
	// STOP OMIT
	for i := 0; i < 2; i++ {
		memcache.Delete(c, "feeds")
		err := <-done
		if err != nil {
			c.Errorf("error storing feed: %v", err)
			return
		}
	}
}

// STOP OMIT

func progginator__(w http.ResponseWriter, r *http.Request) {
	begin := time.Now() // OMIT
	c := appengine.NewContext(r)
	feeds := make([]Feed, 2)
	keys := []*datastore.Key{
		datastore.NewKey(c, "Feed", "proggit", 0, nil),
		datastore.NewKey(c, "Feed", "hackernews", 0, nil),
	}
	err := datastore.GetMulti(c, keys, feeds)
	if err != nil {
		c.Errorf("error getting feed from datastore: %v", err)
		return
	}
	// Render feeds
	// ...
	// STOP OMIT
	w.Header().Add("Content-Type", "text/plain; charset=utf-8")
	for _, feed := range feeds {
		for _, item := range feed.Items {
			fmt.Fprintf(w, "%s: %s\n", item.Title, item.URL)
		}
	}
	c.Infof("progginator__: %s", time.Since(begin)) // OMIT
}

// STOP OMIT

func progginator___(w http.ResponseWriter, r *http.Request) {
	begin := time.Now() // OMIT
	c := appengine.NewContext(r)
	feeds := make([]Feed, 2)
	_, err := memcache.Gob.Get(c, "feeds", &feeds)
	if err != nil {
		// Get feeds from datastore
		// ...
		keys := []*datastore.Key{ // OMIT
			datastore.NewKey(c, "Feed", "proggit", 0, nil), // OMIT
			datastore.NewKey(c, "Feed", "hackernews", 0, nil), // OMIT
		} // OMIT
		err := datastore.GetMulti(c, keys, feeds) // OMIT
		if err != nil { // OMIT
			c.Errorf("error getting feed from datastore: %v", err) // OMIT
			return // OMIT
		} // OMIT
		_ = memcache.Gob.Set(c, &memcache.Item{
			Key: "feeds",
			Object: feeds,
		})
	}
	// Render feeds
	// ...
	// STOP OMIT
	w.Header().Add("Content-Type", "text/plain; charset=utf-8")
	for _, feed := range feeds {
		for _, item := range feed.Items {
			fmt.Fprintf(w, "%s: %s\n", item.Title, item.URL)
		}
	}
	c.Infof("progginator___: %s", time.Since(begin)) // OMIT
}
// STOP OMIT
